React ํ ํ ์คํธ์ ๋ํ ์ข ํฉ ๊ฐ์ด๋. ๋ค์ํ ์ ๋ต, ๋๊ตฌ, ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ค๋ฃจ์ด React ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๋ขฐ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
ํ ํ ์คํธ: ๊ฒฌ๊ณ ํ ์ปดํฌ๋ํธ๋ฅผ ์ํ React ํ ์คํ ์ ๋ต
React ํ ์ ํจ์ํ ์ปดํฌ๋ํธ๊ฐ ์ํ์ ์ฌ์ด๋ ์ดํํธ๋ฅผ ๊ด๋ฆฌํ ์ ์๊ฒ ํ์ฌ ์ฐ๋ฆฌ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ์์ ํ๋ช ์ ์ผ์ผ์ผฐ์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด ์๋ก์ด ํ์๋ ์ด๋ฌํ ํ ์ด ์ฒ ์ ํ ํ ์คํธ๋๋๋ก ๋ณด์ฅํด์ผ ํ๋ ์ฑ ์์ด ๋ฐ๋ฆ ๋๋ค. ์ด ์ข ํฉ ๊ฐ์ด๋์์๋ React ํ ์ ํ ์คํธํ๊ธฐ ์ํ ๋ค์ํ ์ ๋ต, ๋๊ตฌ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ํ์ํ์ฌ React ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๋ขฐ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋ณด์ฅํฉ๋๋ค.
์ ํ ์ ํ ์คํธํด์ผ ํ ๊น์?
ํ ์ ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ์ฝ๊ฒ ๊ณต์ ํ ์ ์๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋ก์ง์ ์บก์ํํฉ๋๋ค. ํ ์ ํ ์คํธํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ช ๊ฐ์ง ์ฃผ์ ์ด์ ์ด ์์ต๋๋ค:
- ๊ณ ๋ฆฝ(Isolation): ํ ์ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธํ ์ ์์ด, ์ฃผ๋ณ ์ปดํฌ๋ํธ์ ๋ณต์ก์ฑ ์์ด ํ ์ ํฌํจ๋ ํน์ ๋ก์ง์ ์ง์คํ ์ ์์ต๋๋ค.
- ์ฌ์ฌ์ฉ์ฑ(Reusability): ์ฒ ์ ํ๊ฒ ํ ์คํธ๋ ํ ์ ๋ ์ ๋ขฐํ ์ ์์ผ๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค๋ฅธ ๋ถ๋ถ์ด๋ ๋ค๋ฅธ ํ๋ก์ ํธ์์๋ ์ฝ๊ฒ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์ ์ง๋ณด์์ฑ(Maintainability): ์ ํ ์คํธ๋ ํ ์ ํ ์ ๋ก์ง ๋ณ๊ฒฝ์ด ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ์๊ธฐ์น ์์ ๋ฒ๊ทธ๋ฅผ ์ ๋ฐํ ๊ฐ๋ฅ์ฑ์ ์ค์ฌ์ฃผ๋ฏ๋ก, ๋ณด๋ค ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฒ ์ด์ค์ ๊ธฐ์ฌํฉ๋๋ค.
- ์์ ๊ฐ(Confidence): ํฌ๊ด์ ์ธ ํ ์คํธ๋ ํ ์ ์ ํ์ฑ์ ๋ํ ์์ ๊ฐ์ ์ ๊ณตํ์ฌ ๋ ๊ฒฌ๊ณ ํ๊ณ ์ ๋ขฐํ ์ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ด์ด์ง๋๋ค.
ํ ํ ์คํธ๋ฅผ ์ํ ๋๊ตฌ ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
React ํ ํ ์คํธ๋ฅผ ๋์์ฃผ๋ ์ฌ๋ฌ ๋๊ตฌ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์ต๋๋ค:
- Jest: ๋ชจํน, ์ค๋ ์ท ํ ์คํ , ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ฑ ํฌ๊ด์ ์ธ ๊ธฐ๋ฅ ์ธํธ๋ฅผ ์ ๊ณตํ๋ ์ธ๊ธฐ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํ ํ๋ ์์ํฌ์ ๋๋ค. Jest๋ ์ข ์ข React ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํจ๊ป ์ฌ์ฉ๋ฉ๋๋ค.
- React Testing Library: ์ฌ์ฉ์์ ๊ด์ ์์ ์ปดํฌ๋ํธ๋ฅผ ํ ์คํธํ๋ ๋ฐ ์ค์ ์ ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์ฌ์ฉ์๊ฐ ์ปดํฌ๋ํธ์ ์ํธ์์ฉํ๋ ๋ฐฉ์๊ณผ ๋์ผํ๊ฒ ํ ์คํธ๋ฅผ ์์ฑํ๋๋ก ๊ถ์ฅํฉ๋๋ค. React ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ ๊ณผ ์ ์๋ํ๋ฉฐ, ํ ์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ณ ์ํธ์์ฉํ๊ธฐ ์ํ ์ ํธ๋ฆฌํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- @testing-library/react-hooks: (ํ์ฌ๋ ์ฌ์ฉ๋์ง ์์ผ๋ฉฐ ๊ธฐ๋ฅ์ด React ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํตํฉ๋จ) ํ ์ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธํ๊ธฐ ์ํ ์ ์ฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ต๋๋ค. ์ฌ์ฉ์ด ์ค๋จ๋์์ง๋ง ๊ทธ ์์น์ ์ฌ์ ํ ์ ํจํฉ๋๋ค. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ ์ ํธ์ถํ๋ ์ปค์คํ ํ ์คํธ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ณ , props๋ฅผ ์ ๋ฐ์ดํธํ๊ณ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์ ํธ๋ฆฌํฐ๋ฅผ ์ ๊ณตํ์ต๋๋ค. ๊ทธ ๊ธฐ๋ฅ์ React ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ด์ ๋์์ต๋๋ค.
- Enzyme: (ํ์ฌ๋ ๋ ์ฌ์ฉ๋จ) ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ์ง ์๊ณ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธํ ์ ์๊ฒ ํด์ฃผ๋ ์์ ๋ ๋๋ง API๋ฅผ ์ ๊ณตํ๋ ๊ตฌํ ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์ผ๋ถ ํ๋ก์ ํธ์์๋ ์ฌ์ ํ ์ฌ์ฉ๋์ง๋ง, ์ฌ์ฉ์ ์ค์ฌ ํ ์คํ ์ ์ค์ ์ ๋ React ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์ ํธ๋ฉ๋๋ค.
๋ค์ํ ์ ํ์ ํ ์ ๋ํ ํ ์คํ ์ ๋ต
์ ์ฉํ ํน์ ํ ์คํ ์ ๋ต์ ํ ์คํธํ๋ ํ ์ ์ ํ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ์๋๋ฆฌ์ค์ ๊ถ์ฅ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค:
1. ๊ฐ๋จํ ์ํ ํ (useState) ํ ์คํธํ๊ธฐ
์ํ ํ ์ ์ปดํฌ๋ํธ ๋ด์ ๊ฐ๋จํ ์ํ ์กฐ๊ฐ์ ๊ด๋ฆฌํฉ๋๋ค. ์ด๋ฌํ ํ ์ ํ ์คํธํ๋ ค๋ฉด React ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ ์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ ๋ค์, ์ปดํฌ๋ํธ์ ์ํธ์์ฉํ์ฌ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ํธ๋ฆฌ๊ฑฐํ ์ ์์ต๋๋ค. ์ํ๊ฐ ์์๋๋ก ์ ๋ฐ์ดํธ๋๋์ง ํ์ธํฉ๋๋ค.
์์:
```javascript // CounterHook.js import { useState } from 'react'; const useCounter = (initialValue = 0) => { const [count, setCount] = useState(initialValue); const increment = () => { setCount(count + 1); }; const decrement = () => { setCount(count - 1); }; return { count, increment, decrement }; }; export default useCounter; ``` ```javascript // CounterHook.test.js import { render, screen, fireEvent } from '@testing-library/react'; import useCounter from './CounterHook'; function CounterComponent() { const { count, increment, decrement } = useCounter(0); return (Count: {count}
2. ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ ํ (useEffect) ํ ์คํธํ๊ธฐ
์ดํํธ ํ ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ๋ ์ด๋ฒคํธ ๊ตฌ๋ ๊ณผ ๊ฐ์ ์ฌ์ด๋ ์ดํํธ๋ฅผ ์ํํฉ๋๋ค. ์ด๋ฌํ ํ ์ ํ ์คํธํ๋ ค๋ฉด ์ธ๋ถ ์์กด์ฑ์ ๋ชจํนํ๊ฑฐ๋ ๋น๋๊ธฐ ํ ์คํ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ฃ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ ค์ผ ํ ์ ์์ต๋๋ค.
์์:
```javascript // DataFetchingHook.js import { useState, useEffect } from 'react'; const useDataFetching = (url) => { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const json = await response.json(); setData(json); } catch (error) { setError(error); } finally { setLoading(false); } }; fetchData(); }, [url]); return { data, loading, error }; }; export default useDataFetching; ``` ```javascript // DataFetchingHook.test.js import { renderHook, waitFor } from '@testing-library/react'; import useDataFetching from './DataFetchingHook'; global.fetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve({ name: 'Test Data' }), }) ); test('fetches data successfully', async () => { const { result } = renderHook(() => useDataFetching('https://example.com/api')); await waitFor(() => expect(result.current.loading).toBe(false)); expect(result.current.data).toEqual({ name: 'Test Data' }); expect(result.current.error).toBe(null); }); test('handles fetch error', async () => { global.fetch = jest.fn(() => Promise.resolve({ ok: false, status: 404, }) ); const { result } = renderHook(() => useDataFetching('https://example.com/api')); await waitFor(() => expect(result.current.loading).toBe(false)); expect(result.current.error).toBeInstanceOf(Error); }); ```์ฐธ๊ณ : `renderHook` ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ํ ์ ์ปดํฌ๋ํธ๋ก ๊ฐ์ ํ์ ์์ด ๋ ๋ฆฝ์ ์ผ๋ก ๋ ๋๋งํ ์ ์์ต๋๋ค. `waitFor`๋ `useEffect` ํ ์ ๋น๋๊ธฐ์ ํน์ฑ์ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
3. ์ปจํ ์คํธ ํ (useContext) ํ ์คํธํ๊ธฐ
์ปจํ ์คํธ ํ ์ React ์ปจํ ์คํธ์ ๊ฐ์ ์๋นํฉ๋๋ค. ์ด๋ฌํ ํ ์ ํ ์คํธํ๋ ค๋ฉด ํ ์คํธ ์ค์ ๋ชจ์ ์ปจํ ์คํธ ๊ฐ์ ์ ๊ณตํด์ผ ํฉ๋๋ค. ์ด๋ ํ ์คํธ์์ ํ ์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๋ฅผ ์ปจํ ์คํธ ํ๋ก๋ฐ์ด๋๋ก ๊ฐ์ธ์ ๋ฌ์ฑํ ์ ์์ต๋๋ค.
์์:
```javascript // ThemeContext.js import React, { createContext, useState } from 'react'; export const ThemeContext = createContext(); export const ThemeProvider = ({ children }) => { const [theme, setTheme] = useState('light'); const toggleTheme = () => { setTheme(theme === 'light' ? 'dark' : 'light'); }; return (Theme: {theme}
4. ๋ฆฌ๋์ ํ (useReducer) ํ ์คํธํ๊ธฐ
๋ฆฌ๋์ ํ ์ ๋ฆฌ๋์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ณต์กํ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ์ด๋ฌํ ํ ์ ํ ์คํธํ๋ ค๋ฉด ๋ฆฌ๋์์ ์ก์ ์ ๋์คํจ์นํ๊ณ ์ํ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋๋์ง ํ์ธํ ์ ์์ต๋๋ค.
์์:
```javascript // CounterReducerHook.js import { useReducer } from 'react'; const reducer = (state, action) => { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: return state; } }; const useCounterReducer = (initialValue = 0) => { const [state, dispatch] = useReducer(reducer, { count: initialValue }); const increment = () => { dispatch({ type: 'increment' }); }; const decrement = () => { dispatch({ type: 'decrement' }); }; return { count: state.count, increment, decrement, dispatch }; // ํ ์คํธ๋ฅผ ์ํด dispatch ๋ ธ์ถ }; export default useCounterReducer; ``` ```javascript // CounterReducerHook.test.js import { renderHook, act } from '@testing-library/react'; import useCounterReducer from './CounterReducerHook'; test('increments the counter using dispatch', () => { const { result } = renderHook(() => useCounterReducer(0)); act(() => { result.current.dispatch({type: 'increment'}); }); expect(result.current.count).toBe(1); }); test('decrements the counter using dispatch', () => { const { result } = renderHook(() => useCounterReducer(0)); act(() => { result.current.dispatch({ type: 'decrement' }); }); expect(result.current.count).toBe(-1); }); test('increments the counter using increment function', () => { const { result } = renderHook(() => useCounterReducer(0)); act(() => { result.current.increment(); }); expect(result.current.count).toBe(1); }); test('decrements the counter using decrement function', () => { const { result } = renderHook(() => useCounterReducer(0)); act(() => { result.current.decrement(); }); expect(result.current.count).toBe(-1); }); ```์ฐธ๊ณ : React ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ `act` ํจ์๋ ๋์คํจ์น ํธ์ถ์ ๊ฐ์ธ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ์ด๋ฅผ ํตํด ๋ชจ๋ ์ํ ์ ๋ฐ์ดํธ๊ฐ ์ด์ค์ ์ด ์ด๋ฃจ์ด์ง๊ธฐ ์ ์ ์ ์ ํ๊ฒ ์ผ๊ด ์ฒ๋ฆฌ๋๊ณ ์ ์ฉ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
5. ์ฝ๋ฐฑ ํ (useCallback) ํ ์คํธํ๊ธฐ
์ฝ๋ฐฑ ํ ์ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํ๊ธฐ ์ํด ํจ์๋ฅผ ๋ฉ๋ชจ์ด์ ์ด์ ํฉ๋๋ค. ์ด๋ฌํ ํ ์ ํ ์คํธํ๋ ค๋ฉด ์์กด์ฑ์ด ๋ณ๊ฒฝ๋์ง ์์์ ๋ ์ฌ๋ฌ ๋ ๋๋ง์ ๊ฑธ์ณ ํจ์ ์๋ณ์๊ฐ ๋์ผํ๊ฒ ์ ์ง๋๋์ง ํ์ธํด์ผ ํฉ๋๋ค.
์์:
```javascript // useCallbackHook.js import { useState, useCallback } from 'react'; const useMemoizedCallback = () => { const [count, setCount] = useState(0); const increment = useCallback(() => { setCount(prevCount => prevCount + 1); }, []); // ์์กด์ฑ ๋ฐฐ์ด์ด ๋น์ด ์์ return { count, increment }; }; export default useMemoizedCallback; ``` ```javascript // useCallbackHook.test.js import { renderHook, act } from '@testing-library/react'; import useMemoizedCallback from './useCallbackHook'; test('increment function remains the same', () => { const { result, rerender } = renderHook(() => useMemoizedCallback()); const initialIncrement = result.current.increment; act(() => { result.current.increment(); }); rerender(); expect(result.current.increment).toBe(initialIncrement); }); test('increments the count', () => { const { result } = renderHook(() => useMemoizedCallback()); act(() => { result.current.increment(); }); expect(result.current.count).toBe(1); }); ```6. Ref ํ (useRef) ํ ์คํธํ๊ธฐ
Ref ํ ์ ์ฌ๋ฌ ๋ ๋๋ง์ ๊ฑธ์ณ ์ง์๋๋ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ์ฐธ์กฐ๋ฅผ ์์ฑํฉ๋๋ค. ์ด๋ฌํ ํ ์ ํ ์คํธํ๋ ค๋ฉด ref ๊ฐ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋๊ณ ์ฌ๋ฌ ๋ ๋๋ง์ ๊ฑธ์ณ ๊ทธ ๊ฐ์ ์ ์งํ๋์ง ํ์ธํด์ผ ํฉ๋๋ค.
์์:
```javascript // useRefHook.js import { useRef, useEffect } from 'react'; const usePrevious = (value) => { const ref = useRef(); useEffect(() => { ref.current = value; }, [value]); return ref.current; }; export default usePrevious; ``` ```javascript // useRefHook.test.js import { renderHook } from '@testing-library/react'; import usePrevious from './useRefHook'; test('returns undefined on initial render', () => { const { result } = renderHook(() => usePrevious(1)); expect(result.current).toBeUndefined(); }); test('returns the previous value after update', () => { const { result, rerender } = renderHook((value) => usePrevious(value), { initialProps: 1 }); rerender(2); expect(result.current).toBe(1); rerender(3); expect(result.current).toBe(2); }); ```7. ์ปค์คํ ํ ํ ์คํธํ๊ธฐ
์ปค์คํ ํ ์ ํ ์คํธํ๋ ๊ฒ์ ๋ด์ฅ ํ ์ ํ ์คํธํ๋ ๊ฒ๊ณผ ์ ์ฌํฉ๋๋ค. ํต์ฌ์ ํ ์ ๋ก์ง์ ๋ถ๋ฆฌํ๊ณ ์ ๋ ฅ๊ณผ ์ถ๋ ฅ์ ๊ฒ์ฆํ๋ ๋ฐ ์ง์คํ๋ ๊ฒ์ ๋๋ค. ์ปค์คํ ํ ์ด ์ํํ๋ ์์ (์ํ ๊ด๋ฆฌ, ์ฌ์ด๋ ์ดํํธ, ์ปจํ ์คํธ ์ฌ์ฉ ๋ฑ)์ ๋ฐ๋ผ ์์์ ์ธ๊ธํ ์ ๋ต๋ค์ ๊ฒฐํฉํ ์ ์์ต๋๋ค.
ํ ํ ์คํธ๋ฅผ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
๋ค์์ React ํ ์ ํ ์คํธํ ๋ ์ผ๋์ ๋์ด์ผ ํ ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ๋ชจ๋ฒ ์ฌ๋ก์ ๋๋ค:
- ๋จ์ ํ ์คํธ ์์ฑ: ๋ ํฐ ์ปดํฌ๋ํธ์ ์ผ๋ถ๋ก ํ ์คํธํ๊ธฐ๋ณด๋ค๋ ํ ์ ๋ก์ง์ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธํ๋ ๋ฐ ์ง์คํ์ธ์.
- React ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ: React ํ ์คํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ฌ์ฉ์ ์ค์ฌ ํ ์คํธ๋ฅผ ์ฅ๋ คํ์ฌ, ํ ์คํธ๊ฐ ์ฌ์ฉ์๊ฐ ์ปดํฌ๋ํธ์ ์ํธ์์ฉํ๋ ๋ฐฉ์์ ๋ฐ์ํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
- ์์กด์ฑ ๋ชจํน: API ํธ์ถ์ด๋ ์ปจํ ์คํธ ๊ฐ๊ณผ ๊ฐ์ ์ธ๋ถ ์์กด์ฑ์ ๋ชจํนํ์ฌ ํ ์ ๋ก์ง์ ๋ถ๋ฆฌํ๊ณ ์ธ๋ถ ์์ธ์ด ํ ์คํธ์ ์ํฅ์ ๋ฏธ์น๋ ๊ฒ์ ๋ฐฉ์งํ์ธ์.
- ๋น๋๊ธฐ ํ ์คํ ๊ธฐ์ ์ฌ์ฉ: ํ ์ด ์ฌ์ด๋ ์ดํํธ๋ฅผ ์ํํ๋ ๊ฒฝ์ฐ, `waitFor`๋ `findBy*` ๋ฉ์๋์ ๊ฐ์ ๋น๋๊ธฐ ํ ์คํ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ์ด์ค์ ์ ๋ง๋ค๊ธฐ ์ ์ ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ฃ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ์ธ์.
- ๊ฐ๋ฅํ ๋ชจ๋ ์๋๋ฆฌ์ค ํ ์คํธ: ๊ฐ๋ฅํ ๋ชจ๋ ์ ๋ ฅ ๊ฐ, ์ฃ์ง ์ผ์ด์ค, ์ค๋ฅ ์กฐ๊ฑด์ ๋ค๋ฃจ์ด ํ ์ด ๋ชจ๋ ์ํฉ์์ ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ๋์ง ํ์ธํ์ธ์.
- ํ ์คํธ๋ฅผ ๊ฐ๊ฒฐํ๊ณ ์ฝ๊ธฐ ์ฝ๊ฒ ์ ์ง: ์ดํดํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ํ ์คํธ๋ฅผ ์์ฑํ์ธ์. ํ ์คํธ์ ์ด์ค์ ์ ์์ ์ ์ธ ์ด๋ฆ์ ์ฌ์ฉํ์ธ์.
- ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๊ณ ๋ ค: ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ ์์ ์ ์ ํ๊ฒ ํ ์คํธ๋์ง ์์ ์์ญ์ ์๋ณํ์ธ์.
- Arrange-Act-Assert ํจํด ๋ฐ๋ฅด๊ธฐ: ํ ์คํธ๋ฅผ arrange(ํ ์คํธ ํ๊ฒฝ ์ค์ ), act(ํ ์คํธํ๋ ค๋ ์์ ์ํ), assert(์์ ์ด ์์๋ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํ๋์ง ํ์ธ)์ ์ธ ๊ฐ์ง ๋ช ํํ ๋จ๊ณ๋ก ๊ตฌ์ฑํ์ธ์.
ํผํด์ผ ํ ์ผ๋ฐ์ ์ธ ํจ์
๋ค์์ React ํ ์ ํ ์คํธํ ๋ ํผํด์ผ ํ ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ํจ์ ์ ๋๋ค:
- ๊ตฌํ ์ธ๋ถ ์ฌํญ์ ๋ํ ๊ณผ๋ํ ์์กด: ํ ์ ๊ตฌํ ์ธ๋ถ ์ฌํญ๊ณผ ๋ฐ์ ํ๊ฒ ๊ฒฐํฉ๋ ํ ์คํธ ์์ฑ์ ํผํ์ธ์. ์ฌ์ฉ์์ ๊ด์ ์์ ํ ์ ๋์์ ํ ์คํธํ๋ ๋ฐ ์ง์คํ์ธ์.
- ๋น๋๊ธฐ ๋์ ๋ฌด์: ๋น๋๊ธฐ ๋์์ ์ ๋๋ก ์ฒ๋ฆฌํ์ง ๋ชปํ๋ฉด ๋ถ์์ ํ๊ฑฐ๋ ๋ถ์ ํํ ํ ์คํธ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ์ฌ์ด๋ ์ดํํธ๊ฐ ์๋ ํ ์ ํ ์คํธํ ๋๋ ํญ์ ๋น๋๊ธฐ ํ ์คํ ๊ธฐ์ ์ ์ฌ์ฉํ์ธ์.
- ์์กด์ฑ ๋ชจํนํ์ง ์๊ธฐ: ์ธ๋ถ ์์กด์ฑ์ ๋ชจํนํ์ง ์์ผ๋ฉด ํ ์คํธ๊ฐ ๊นจ์ง๊ธฐ ์ฝ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ด๋ ค์์ง ์ ์์ต๋๋ค. ํญ์ ์์กด์ฑ์ ๋ชจํนํ์ฌ ํ ์ ๋ก์ง์ ๋ถ๋ฆฌํ์ธ์.
- ๋จ์ผ ํ ์คํธ์ ๋๋ฌด ๋ง์ ์ด์ค์ ์์ฑ: ๋จ์ผ ํ ์คํธ์ ๋๋ฌด ๋ง์ ์ด์ค์ ์ ์์ฑํ๋ฉด ์คํจ์ ๊ทผ๋ณธ ์์ธ์ ์๋ณํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค. ๋ณต์กํ ํ ์คํธ๋ฅผ ๋ ์๊ณ ์ง์ค๋ ํ ์คํธ๋ก ๋๋์ธ์.
- ์ค๋ฅ ์กฐ๊ฑด ํ ์คํธํ์ง ์๊ธฐ: ์ค๋ฅ ์กฐ๊ฑด์ ํ ์คํธํ์ง ์์ผ๋ฉด ํ ์ด ์๊ธฐ์น ์์ ๋์์ ์ทจ์ฝํด์ง ์ ์์ต๋๋ค. ํญ์ ํ ์ด ์ค๋ฅ์ ์์ธ๋ฅผ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋์ง ํ ์คํธํ์ธ์.
๊ณ ๊ธ ํ ์คํ ๊ธฐ๋ฒ
๋ ๋ณต์กํ ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ, ๋ค์๊ณผ ๊ฐ์ ๊ณ ๊ธ ํ ์คํ ๊ธฐ๋ฒ์ ๊ณ ๋ คํด ๋ณด์ธ์:
- ์์ฑ ๊ธฐ๋ฐ ํ ์คํ : ๋ค์ํ ์๋๋ฆฌ์ค์ ๊ฑธ์ณ ํ ์ ๋์์ ํ ์คํธํ๊ธฐ ์ํด ๊ด๋ฒ์ํ ๋ฌด์์ ์ ๋ ฅ์ ์์ฑํฉ๋๋ค. ์ด๋ ์ ํต์ ์ธ ๋จ์ ํ ์คํธ๋ก ๋์น ์ ์๋ ์ฃ์ง ์ผ์ด์ค์ ์๊ธฐ์น ์์ ๋์์ ๋ฐ๊ฒฌํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- ๋ฎคํ ์ด์ ํ ์คํ : ํ ์ ์ฝ๋์ ์์ ๋ณ๊ฒฝ(๋ฎคํ ์ด์ )์ ๋์ ํ๊ณ , ๊ทธ ๋ณ๊ฒฝ์ด ํ ์ ๊ธฐ๋ฅ์ ๋ง๊ฐ๋จ๋ฆด ๋ ํ ์คํธ๊ฐ ์คํจํ๋์ง ํ์ธํฉ๋๋ค. ์ด๋ ํ ์คํธ๊ฐ ์ค์ ๋ก ์ฌ๋ฐ๋ฅธ ๊ฒ์ ํ ์คํธํ๊ณ ์๋์ง ํ์ธํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- ๊ณ์ฝ ํ ์คํ : ํ ์ ์์ ๋์์ ๋ช ์ํ๋ ๊ณ์ฝ์ ์ ์ํ ๋ค์, ํ ์ด ํด๋น ๊ณ์ฝ์ ์ค์ํ๋์ง ํ์ธํ๋ ํ ์คํธ๋ฅผ ์์ฑํฉ๋๋ค. ์ด๋ ์ธ๋ถ ์์คํ ๊ณผ ์ํธ์์ฉํ๋ ํ ์ ํ ์คํธํ ๋ ํนํ ์ ์ฉํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
React ํ ํ ์คํธ๋ ๊ฒฌ๊ณ ํ๊ณ ์ ์ง๋ณด์ ๊ฐ๋ฅํ React ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ์ด ๊ฐ์ด๋์์ ์ค๋ช ํ ์ ๋ต๊ณผ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ฉด ํ ์ด ์ฒ ์ ํ ํ ์คํธ๋๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ๋ขฐํ ์ ์๊ณ ๋ณต์๋ ฅ์ด ์์์ ๋ณด์ฅํ ์ ์์ต๋๋ค. ์ฌ์ฉ์ ์ค์ฌ ํ ์คํธ์ ์ง์คํ๊ณ , ์์กด์ฑ์ ๋ชจํนํ๊ณ , ๋น๋๊ธฐ ๋์์ ์ฒ๋ฆฌํ๊ณ , ๊ฐ๋ฅํ ๋ชจ๋ ์๋๋ฆฌ์ค๋ฅผ ๋ค๋ฃจ๋ ๊ฒ์ ๊ธฐ์ตํ์ธ์. ํฌ๊ด์ ์ธ ํ ํ ์คํธ์ ํฌ์ํจ์ผ๋ก์จ ์ฝ๋์ ๋ํ ์์ ๊ฐ์ ์ป๊ณ React ํ๋ก์ ํธ์ ์ ๋ฐ์ ์ธ ํ์ง์ ํฅ์์ํฌ ์ ์์ต๋๋ค. ํ ์คํธ๋ฅผ ๊ฐ๋ฐ ์ํฌํ๋ก์ฐ์ ํ์์ ์ธ ๋ถ๋ถ์ผ๋ก ๋ฐ์๋ค์ด๋ฉด ๋ ์์ ์ ์ด๊ณ ์์ธก ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณด์์ ์ป๊ฒ ๋ ๊ฒ์ ๋๋ค.
์ด ๊ฐ์ด๋๋ React ํ ํ ์คํธ๋ฅผ ์ํ ๊ฒฌ๊ณ ํ ๊ธฐ๋ฐ์ ์ ๊ณตํ์ต๋๋ค. ๋ ๋ง์ ๊ฒฝํ์ ์์ผ๋ฉด์ ๋ค์ํ ํ ์คํ ๊ธฐ๋ฒ์ ์คํํ๊ณ ํ๋ก์ ํธ์ ํน์ ์๊ตฌ์ ๋ง๊ฒ ์ ๊ทผ ๋ฐฉ์์ ์กฐ์ ํด ๋ณด์ธ์. ์ฆ๊ฑฐ์ด ํ ์คํ ๋์ธ์!